package com.gitee.wsl.result

import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract

interface StateEntryResult<out V, out E,out S>: EntryResult<V, E> {

    @Suppress("UNCHECKED_CAST")
    val stateValue: S

    val isStateValue:Boolean

    operator fun component3(): S?

}

/**
 * Unsafely casts this [Result<V, E>][ValueResult] to [Result<U, Nothing>][ValueResult], to be used inside
 * an explicit [isOk][ValueResult.isOk] or [isErr][ValueResult.isErr] guard.
 */
@Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE")
 inline fun <V, E, S, U> StateEntryResult<V, E, S>.asOk(): StateEntryResult<U, Nothing, Nothing> {
    return this as StateEntryResult<U, Nothing, Nothing>
}

/**
 * Unsafely casts this [Result<V, E>][ValueResult] to [Result<Nothing, F>][ValueResult], to be used inside
 * an explicit [isOk][ValueResult.isOk] or [isErr][ValueResult.isErr] guard.
 */
@Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE")
 inline fun <V, E,S, F> StateEntryResult<V, E, S>.asErr(): StateEntryResult<Nothing, F, Nothing> {
    return this as StateEntryResult<Nothing, F, Nothing>
}

@Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE")
 inline fun <V, E, S, F> StateEntryResult<V, E, S>.asStateValue(): StateEntryResult<Nothing, Nothing, S> {
    return this as StateEntryResult<Nothing, Nothing, S>
}

@Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE")
 inline fun <V, E,S, F> StateEntryResult<V, E, S>.asStateValue(newState:S): StateEntryResult<Nothing, Nothing, S> {
    return this as StateEntryResult<Nothing, Nothing, S>
}

@OptIn(ExperimentalContracts::class)
inline fun < V,  E, S, T: StateEntryResult<V, E, S>> T.onStateChange(action: (value: S) -> Unit): T {
    contract {
        callsInPlace(action, InvocationKind.AT_MOST_ONCE)
    }
    if (this.isStateValue) action(stateValue)
    return this
}